package org.megha.blog.example.part18;

/**
 * Some examples to demonstrate what works, and what doesn't related to type-casting.
 * 
 * @author megha birmiwal
 */
public class TypeCasting {

	public static class A {}
	
	public static class B1 extends A {}
	public static class B2 extends A {}
	
	public static class C extends B1 {}

	public static void main(String args[]) {
		A a = new A();
		B1 b1 = new B1();
		B2 b2 = new B2();
		C c = new C();
		
		// up-casting; no explicit casts required
		A ax = b1;
		ax = b2;
		ax = c;
		
		// down-casting: explicit casting required
		ax = b1;
		b1 = (B1) ax;
		ax = c;
		c = (C) ax;
		
		// cannot down-cast parent to child; throws exception
		try {
			c = (C) b1;
		} catch (ClassCastException e) {
			// do nothing about it for now
		}
		
		B1 bx = c;
		ax = bx;
		bx = (B1) ax;
		bx = (C) ax; // (C) ax -> down-casting; then bx = ((C) ax) is upcasting
		
		Shape s1 = new Circle(5.0);
		Circle c1 = ((Circle) s1);
		
		System.out.println("is s1 a Circle: " + (s1 instanceof Circle));
		System.out.println("is s1 a Rectangle: " + (s1 instanceof Rectangle));
		printParameters(s1);
		printParameters(new Rectangle(1, 2));
		
		// cannot assign C to B2
		// compilation error
		// b2 = c;
		
		// explicit casting - compilation error
		// b2 = (B2) c;
		
		// trying to workaround - throws ClassCastException
		ax = c;
		b2 = (B2) ax; // throws class-cast-exception
		
		// Object is super-class of all objects.
		// b2 = (B2) x; doesn't give compilation errors, but may throw an exception if the types don't match,
		// to avoid those exceptions, check with 'instanceof' operator
		Object x = new Rectangle(3, 5);
		if (x instanceof B2) {
			b2 = (B2) x;
		}
	}
	
	/** Takes any Shape and then prints shape specific details */
	public static void printParameters(Shape s) {
		if (s instanceof Circle) {
			Circle c = (Circle) s;
			System.out.println("radius: " + c.getRadius());
			return;
		}
		
		if (s instanceof Rectangle) {
			Rectangle r = (Rectangle) s;
			System.out.println("l,b: " + r.getLength() + "," + r.getBreadth());
			return;
		}
		
		System.out.println("unknown shape");
	}
}
